﻿using DLLPC.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace VisionCore.FASTUS
{
    /// <summary>
    /// FASTUS(OPTEX)激光位移传感器
    /// </summary>
    public class LaserDispHelper
    {
        private double msValue = 0;

        /// <summary>
        /// 上-->下(近-->远)  +-->- 
        /// </summary>
        public double MsValue
        {
            get
            {
                return msValue * 1;
            }
        }

        private TcpClient tcpClient = new TcpClient();
        private SystemTimeCounter sysTimer = new SystemTimeCounter();
        private string _IP = "192.168.0.10";
        private int _Port = 5011;
        public SafeQueue<byte[]> SQ_SendCMD = new SafeQueue<byte[]>();
        public LaserDispHelper(string strIP, int Port = 5011)
        {
            _IP = strIP;
            _Port = Port;
        }

        Thread thread;
        private bool isRun = true;

        private bool enable = true;
        public bool Enable
        {
            get { return enable; }
        }

        private bool connected = false;
        public bool Connected
        {
            get { return connected; }
        }

        public void Start(bool en = true)
        {
            enable = en;
            thread = new Thread(theadFunction);
            thread.IsBackground = true;
            thread.Start();
        }

        public void Quit()
        {
            isRun = false;
        }

        private PollStatus StatusCode = new PollStatus();
        /// <summary>
        /// 采样周期
        /// </summary>
        public double SamplePeriod { get; set; } = 0;
        public bool IsError { get; set; } = false;
        int RetryIdx = 0;
        int timecot = 0;
        private void theadFunction()
        {
            ProcessHelper.SetThreadAffinityMask(ProcessHelper.GetCurrentThread(), new UIntPtr(ProcessHelper.SetCpuID(4)));
            if (!Enable) return;

            StatusCode = PollStatus.Open;
            sysTimer.Start();
            while (isRun)
            {
                switch (StatusCode)
                {
                    case PollStatus.Open:
                        if (Connect() == false)
                        {
                            Thread.Sleep(2000);
                        }
                        else
                        {
                            LogMsg("连接成功！");
                            connected = true;
                            StatusCode = PollStatus.Initial;
                        }
                        break;
                    case PollStatus.Initial:
                        if (InitialFunction() == false)
                        {
                            StatusCode = PollStatus.Error;
                        }
                        else
                        {
                            tcpClient.Client.SendBufferSize = 16;
                            tcpClient.Client.ReceiveBufferSize = 32;
                            StatusCode = PollStatus.Polling;
                        }
                        break;
                    case PollStatus.Polling:
                        if (timecot > 2)
                        {
                            timecot = 0;
                            byte[] sendbytes = new byte[4];
                            sendbytes[0] = 0x30;
                            sendbytes[1] = 0x02;
                            sendbytes[2] = 0x0d;
                            sendbytes[3] = 0x60;
                            SQ_SendCMD.Enqueue(sendbytes);
                        }
                        if (PollingFunction() == false)
                        {
                            if (RetryIdx > 3)
                            {
                                RetryIdx = 0;
                                StatusCode = PollStatus.Error;
                                Thread.Sleep(2000);
                            }
                            RetryIdx++;
                        }
                        else
                        {
                            RetryIdx = 0;
                        }
                        timecot++;
                        break;
                    case PollStatus.Error:
                        ErrorHandle();
                        connected = false;
                        StatusCode = PollStatus.Open;
                        break;
                    default:
                        break;
                }

                IsError = (StatusCode == PollStatus.Polling ? false : true);

                sysTimer.Stop();
                SamplePeriod = sysTimer.Duration;
                sysTimer.Start();

                SystemTimeCounter.timeBeginPeriod(1);
                Thread.Sleep(1);
                SystemTimeCounter.timeEndPeriod(1);
            }

            DisConnect();
        }

        double dblTemp = 0;
        ushort temp = 0;
        bool sending = false;
        int timecot1 = 0;
        private bool PollingFunction()
        {
            try
            {
                //byte[] sendbytes = new byte[4];
                //sendbytes[0] = 0x30;
                //sendbytes[1] = 0x02;
                //sendbytes[2] = 0x0d;
                //sendbytes[3] = 0x60;
                if (timecot1 >100)
                {
                    timecot1 = 0;
                    sending = false;
                }
                if (SQ_SendCMD.Count > 0&& !sending)
                {
                    sending = true;
                    tcpClient.Client.Send(SQ_SendCMD.Dequeue(), 0);
                }

                if (tcpClient.Client.Available > 0)
                {
                    sending = false;
                    byte[] recvbytes = new byte[64];
                    int count = tcpClient.Client.Receive(recvbytes);

                    if (count != 6)
                    {
                        IsError = true;
                        return true;
                    }

                    ushort code = MemoryAccess.GetUshort(recvbytes, 0);

                    if (code == 0xb004)
                    {
                        msValue = MemoryAccess.GetDouble(recvbytes, 2, 6);

                        return true;
                    }
                    else
                    {
                        msValue = -500;
                        return true;
                    }
                }
                
                return true;
            }
            catch (Exception ex)
            {
                LogMsg("read value error:" + ex.Message);
                return false;
            }
        }

        public bool Connect()
        {
            System.Net.IPAddress host = System.Net.IPAddress.Parse(_IP);
            try
            {
                if (tcpClient == null || tcpClient.Client == null)
                {
                    tcpClient = new TcpClient();
                }

                tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 200); // 接收200ms超时
                tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 200);
                if (tcpClient.Connected == false)
                {
                    tcpClient.Connect(host, _Port);
                }
                return true;
            }
            catch (Exception ex)
            {
                LogMsg("Connect error: " + ex.Message);
                return false;
            }
        }

        public void DisConnect()
        {
            try
            {
                if (tcpClient.Connected == true)
                {
                    tcpClient.Close();
                }
            }
            catch (Exception ex)
            {
                LogMsg("DisConnect error: " + ex.Message);
            }
        }

        private bool InitialFunction()
        {
            return true;
        }

        private void ErrorHandle()
        {
            LogMsg("通信错误");
            Thread.Sleep(4000);
        }

        private void LogMsg(string msg)
        {
            string strMsg = string.Format("激光位移传感器 {0}", msg);
            LogHelper.Write(LogHelper.Module.Motion, strMsg);
        }

        internal enum PollStatus
        {
            Open = 0,
            Initial = 4,
            Polling = 10,
            Error = 30
        }
    }
}
